/********************************************************************************
* @file    rgb_hsv.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2020-11-23
* @brief   RGB转HSV
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "rgb_hsv.h"

/* Private Function Prototypes -----------------------------------------------*/
static float min(float a, float b, float c)
{
    float m;

    m = a < b ? a : b;
    return (m < c ? m : c);
}

static float max(float a, float b, float c)
{
    float m;

    m = a > b ? a : b;
    return (m > c ? m : c);
}

/* Public Function Prototypes -----------------------------------------------*/
void rgb2hsv(uint8_t r, uint8_t g, uint8_t b, float *h, float *s, float *v)
{
    float red, green, blue;
    float cmax, cmin, delta;

    red   = (float)r / 255;
    green = (float)g / 255;
    blue  = (float)b / 255;

    cmax = max(red, green, blue);
    cmin = min(red, green, blue);
    delta = cmax - cmin;

    /* H */
    if (delta == 0)
    {
        *h = 0;
    }
    else
    {
        if (cmax == red)
        {
            if (green >= blue)
            {
                *h = 60 * ((green - blue) / delta);
            }
            else
            {
                *h = 60 * ((green - blue) / delta) + 360;
            }
        }
        else if (cmax == green)
        {
            *h = 60 * ((blue - red) / delta + 2);
        }
        else if (cmax == blue)
        {
            *h = 60 * ((red - green) / delta + 4);
        }
    }

    /* S */
    if (cmax == 0)
    {
        *s = 0;
    }
    else
    {
        *s = delta / cmax;
    }

    /* V */
    *v = cmax;
}

void hsv2rgb(float h, float s, float v, uint8_t *r, uint8_t *g, uint8_t *b)
{
    if (s == 0)
    {
        *r = *g = *b = v;
    }
    else
    {
        float H = h / 60;
        int hi  = (int)H;
        float f = H - hi;
        float p = v * (1 - s);
        float q = v * (1 - f * s);
        float t = v * (1 - (1 - f) * s);
        switch (hi)
        {
        case 0:
            *r = (int)(v * 255.0 + 0.5);
            *g = (int)(t * 255.0 + 0.5);
            *b = (int)(p * 255.0 + 0.5);
            break;
        case 1:
            *r = (int)(q * 255.0 + 0.5);
            *g = (int)(v * 255.0 + 0.5);
            *b = (int)(p * 255.0 + 0.5);
            break;
        case 2:
            *r = (int)(p * 255.0 + 0.5);
            *g = (int)(v * 255.0 + 0.5);
            *b = (int)(t * 255.0 + 0.5);
            break;
        case 3:
            *r = (int)(p * 255.0 + 0.5);
            *g = (int)(q * 255.0 + 0.5);
            *b = (int)(v * 255.0 + 0.5);
            break;
        case 4:
            *r = (int)(t * 255.0 + 0.5);
            *g = (int)(p * 255.0 + 0.5);
            *b = (int)(v * 255.0 + 0.5);
            break;
        case 5:
            *r = (int)(v * 255.0 + 0.5);
            *g = (int)(p * 255.0 + 0.5);
            *b = (int)(q * 255.0 + 0.5);
            break;
        default:
            break;
        }
    }
}

/**
  * @brief  将RGB颜色组合到一个32位数据中存储,并返回GRB
  * @param  red：  0-255
  * @param  green：0-255
  * @param  blue： 0-255
  */
uint32_t get_grb_color(uint8_t red, uint8_t green, uint8_t blue)
{
  return green << 16 | red << 8 | blue;
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t get_next_wheel(uint8_t wheelPos)
{
    wheelPos = 255 - wheelPos;
    if (wheelPos < 85)
    {
        return get_grb_color(255 - wheelPos * 3, 0, wheelPos * 3);
    }
    if (wheelPos < 170)
    {
        wheelPos -= 85;
        return get_grb_color(0, wheelPos * 3, 255 - wheelPos * 3);
    }
    wheelPos -= 170;
    return get_grb_color(wheelPos * 3, 255 - wheelPos * 3, 0);
}
